package com.ruyuan.process.engine.config;

import com.ruyuan.process.engine.enums.InvokeMethod;
import com.ruyuan.process.engine.model.ProcessModel;
import com.ruyuan.process.engine.model.ProcessNodeModel;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhonghuashishan
 * @version 1.0
 */
public abstract class XmlProcessParser implements ProcessParser {

    @Override
    public List<ProcessModel> parse() throws Exception {
        // xml解析，一般来说用框架就可以了，SAX框架来做一个解析就可以了
        // xml解析框架，封装了固定的，针对提供的xml配置文件，他会负责基于文件io流读取xml内容
        // 就会对xml内容进行封装返回给我们

        // 这个所谓的document，代表了一份xml文件，xml框架会把xml文件里的内容封装为他的一些类
        Document document = getDocument();
        Element rootElement = document.getRootElement();
        List<Element> processElements = rootElement.elements(); // 针对root标签，就可以拿到子标签

        // 把每个<process>标签以及他子标签的内容，解析封装为对应的ProcessModel数据模型
        List<ProcessModel> processModels = new ArrayList<>();

        // 遍历到每个<process>标签
        for (Element process : processElements) {
            ProcessModel model = new ProcessModel();
            model.setName(process.attributeValue("name"));

            // 获取<process>标签的子标签list，<node>标签集合
            List<Element> elements = process.elements();
            for (Element node : elements) {
                // 每个<node>标签都要封装为对应的ProcessNodeModel数据模型
                ProcessNodeModel processNodeModel = new ProcessNodeModel();
                processNodeModel.setName(node.attributeValue("name"));
                processNodeModel.setClassName(node.attributeValue("class"));

                String next = node.attributeValue("next");
                if (next != null) {
                    processNodeModel.setNextNode(next);
                }

                String begin = node.attributeValue("begin");
                processNodeModel.setBegin(Boolean.parseBoolean(begin));

                String invokeMethodStr = node.attributeValue("invoke-method");
                InvokeMethod invokeMethod = invokeMethodStr == null ? InvokeMethod.SYNC :
                        InvokeMethod.valueOf(invokeMethodStr.toUpperCase());
                processNodeModel.setInvokeMethod(invokeMethod);

                model.addNode(processNodeModel);
            }

            // <process>标签对应的Model就放到一个list集合里去
            processModels.add(model);
        }

        return processModels;
    }

    protected abstract Document getDocument() throws DocumentException;

}
